﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TheNorthStar.Api.Requests;
using TheNorthStar.Domain;
namespace TheNorthStar.Web.Application.Services
{
    public class DriverLoginService : IDriverLoginService
    {
       
        private Repository.NorthStarDbEntities dbDriver = new Repository.NorthStarDbEntities();
        
        public Car GetCar(string carNum)
        {
            //CarDetails myCar = new CarDetails( carNum );
            
            return dbDriver.Cars.SingleOrDefault( x => x.CarNumber == carNum );
        }
        public Driver GetDriverByID(int id)
        {
            return dbDriver.Drivers.SingleOrDefault(x => x.DriverId == id); 
        }
        public Driver GetByUsernameAndPassword(string userName, string password)//,int carnum)
        {
          /*  Driver driver = dbDriver.Drivers.SingleOrDefault(x => x.UserName == userName && x.Password == password);
            Car car = dbDriver.Cars.SingleOrDefault(x => x.CarNumber == carnum);

            if (car == null)
            {
                //throw error;
            }
            driver.CarId = car.CarId;
            dbDriver.SaveChanges();*/

            return dbDriver.Drivers.SingleOrDefault(x => x.UserName == userName && x.Password == password);
            
        }
        public void SetDriverStatus(int driverId, string status)
        {
            Driver currentDriver = dbDriver.Drivers.FirstOrDefault(x => x.DriverId == driverId);
            currentDriver.DriverStatus = status;
            dbDriver.SaveChanges();
        }
        public bool PickedUpBooking(int driverId, int bookingId)
        {
            var booking = dbDriver.Bookings.FirstOrDefault(x => x.BookingId == bookingId);

            if (booking != null && (booking.DriverId == driverId))
            {
                booking.DriverId = driverId;
                SetDriverStatus(driverId, "Working");
                booking.Status = "PICKEDUP";
                dbDriver.SaveChanges();
                return true;
            }

            return false;
        }
        public bool NoShow(int driverId, int bookingId)
        {
            var booking = dbDriver.Bookings.FirstOrDefault(x => x.BookingId == bookingId);

            if (booking != null && (booking.DriverId == driverId))
            {
                booking.DriverId = driverId;
                SetDriverStatus(driverId, "Available");
                booking.Status = "NOSHOW";
                dbDriver.SaveChanges();
                return true;
            }

            return false;
        }
        public bool CompleteJob(int driverId, int bookingId)
        {
            var booking = dbDriver.Bookings.FirstOrDefault(x => x.BookingId == bookingId);

            if (booking != null && booking.DriverId == driverId )
            {
                booking.DriverId = driverId;
                SetDriverStatus(driverId, "Available");
                booking.Status = "FINISHED";
                dbDriver.SaveChanges();
                return true;
            }

            return false;
        }

        public void UpdatePosition(DriverPosition pos)
        {
            int id = 0;
            var res = Int32.TryParse(pos.DriverId, out id);
            if (res)
            {
                Driver driver = dbDriver.Drivers.FirstOrDefault(x => x.DriverId == id);
                if (driver != null)
                {
                    driver.LastKnownLatitude = (decimal) pos.Latitude;
                    driver.LastKnownLongitude = (decimal) pos.Longitude;
                    dbDriver.SaveChanges();
                }
            }
        }

        public bool AcceptBooking(int driverId, int bookingId)
        {
            var booking = dbDriver.Bookings.FirstOrDefault(x => x.BookingId == bookingId);

            if(booking != null && (booking.DriverId == null || booking.DriverId == 0))
            {
                booking.DriverId = driverId;
                SetDriverStatus( driverId, "Confirmed" );
                booking.Status = "CONFIRMED";
                dbDriver.SaveChanges();
                return true;
            }

            return false;
        }
        public Booking RequestWork(int driverId, double lat, double lng)
        {
            //update the driver - this should be done in the driver service..... not sure if pete has already done this...
            Driver currentDriver = dbDriver.Drivers.FirstOrDefault(x => x.DriverId == driverId);
            currentDriver.LastKnownLatitude = (decimal)lat;
            currentDriver.LastKnownLongitude = (decimal)lng;
            dbDriver.SaveChanges();

            var newBookings = dbDriver.Bookings.Where(x => x.Status == "NEW").OrderBy(x => x.CreateDateTime);

            var allDrivers = dbDriver.Drivers.Where(x => x.DriverStatus == "Available").ToList();

            //calcualte distance to driver for all new bookings
            foreach (Booking booking in newBookings)
            {  
                foreach (var driver in allDrivers)
                {
                    driver.DistanceToBooking = haversine_km((double)driver.LastKnownLatitude.Value, (double)driver.LastKnownLongitude.Value, (double)booking.Latitude.Value, (double)booking.Longitude.Value);
                }

                //order all drivers by closeness to booking, then take the 10 closest drivers, order them by the time since last work and then select
                //the top 3 to be our "eligible" available drivers list
                var driverShortList = allDrivers.OrderBy(x => x.DistanceToBooking).Take(5).OrderBy(x => x.ActivatedDateTime.Value).Take(3);

                if (driverShortList.FirstOrDefault(x => x.DriverId == driverId) != null)
                {
                    //driver is in short list and eligible for this booking
                    return booking;
                }

            }

            return null;

        }
        public string GetCustomersAdd(int bookingId)
        {
            var booking = dbDriver.Bookings.FirstOrDefault(x => x.BookingId == bookingId);
            return  booking.PickupUnit + " " 
                    + booking.PickupStreetNumber + " " 
                    + booking.PickupStreet + " " 
                    + booking.PickupStreetType + " " 
                    + booking.PickupSuburb;
        }
        public double haversine_km(double lat1, double long1, double lat2, double long2)
        {
            var d2r = 0.0174532925199433; // Math.PI / 180.0;
            double dlong = (long2 - long1) * d2r;
            double dlat = (lat2 - lat1) * d2r;
            double a = Math.Pow(Math.Sin(dlat / 2.0), 2) + Math.Cos(lat1 * d2r) * Math.Cos(lat2 * d2r) * Math.Pow(Math.Sin(dlong / 2.0), 2);
            double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
            double d = 6367 * c;

            return d;
        }
    }
}